#include "System.hpp"

using namespace luabind;
namespace bind
{
	namespace SL
	{
		namespace system
		{
			void BCode(lua_State* lua, const std::string& ns)
			{
				if (type(globals(lua)[ns.c_str()]) == LUA_TNIL)
					globals(lua)[ns.c_str()] = newtable(lua);

				object status = newtable(lua);
				status["Init"] = sl::StatusCode::Init;
				status["Event"] = sl::StatusCode::Event;
				status["Update"] = sl::StatusCode::Update;
				status["Draw"] = sl::StatusCode::Draw;
				status["Pause"] = sl::StatusCode::Pause;
				status["Quit"] = sl::StatusCode::Quit;
				status["End"] = sl::StatusCode::End;
				globals(lua)[ns.c_str()]["StatusCode"] = status;

				object error = newtable(lua);
				error["NothingSpecific"] = sl::ErrorCode::NothingSpecific;
				error["Bind"] = sl::ErrorCode::Bind;
				error["OpenWindow"] = sl::ErrorCode::OpenWindow;
				error["NoTexture"] = sl::ErrorCode::NoTexture;
				error["LoadTexture"] = sl::ErrorCode::LoadTexture;
				error["LoadXML"] = sl::ErrorCode::LoadXML;
				error["LoadMap"] = sl::ErrorCode::LoadMap;
				error["Other"] = sl::ErrorCode::Other;
				globals(lua)[ns.c_str()]["ErrorCode"] = error;
			}

			void BLogger(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						class_<sl::LogType>("LogType")
							.def("ToString", &sl::LogType::ToString),

						class_<sl::Log>("Log")
							.def(constructor<sl::LogType::Type>())
							.scope
								[
									def("New", &sl::New<sl::Log>)
								]
							.def("Open", &sl::Logger::Open)
							.def("Close", &sl::Logger::Close)
							.def("Write", (sl::Log*(sl::Log::*)(const std::string&))&sl::Log::Write)
							.def("Write", (sl::Log*(sl::Log::*)(sl::LogType::Type, const std::string&))&sl::Log::Write)
							.def("SetLogType", &sl::Log::SetLogType)
							/*.def(self + other<std::string>())
							.def(self + other<sl::LogType::Type>())*/,

						class_<sl::Logger, bases<sl::Log> >("Logger")
							.def(constructor<>())
							.scope
								[
									def("New", &sl::New<sl::Logger>)
								]
							.def("Open", &sl::Logger::Open)
							.def("Close", &sl::Logger::Close)
							.def("Write", (sl::Logger*(sl::Logger::*)(const std::string&))&sl::Logger::Write)
							.def("Write", (sl::Logger*(sl::Logger::*)(sl::LogType::Type, const std::string&))&sl::Logger::Write)
							.def("SetLogType", &sl::Logger::SetLogType),

						class_<sl::FileLogger, bases<sl::Log> >("FileLogger")
							.def(constructor<>())
							.scope
								[
									def("New", &sl::NewFileLogger)
								]
							.def("Open", &sl::FileLogger::Open)
							.def("Close", &sl::FileLogger::Close)
							.def("Write", (sl::FileLogger*(sl::FileLogger::*)(const std::string&))&sl::FileLogger::Write)
							.def("Write", (sl::FileLogger*(sl::FileLogger::*)(sl::LogType::Type, const std::string&))&sl::FileLogger::Write)
							.def("SetLogType", &sl::FileLogger::SetLogType)
					];

				object type = newtable(lua);
				type["None"] = sl::LogType::None;
				type["Info"] = sl::LogType::Info;
				type["Warning"] = sl::LogType::Warning;
				type["Error"] = sl::LogType::Error;
				globals(lua)[ns.c_str()]["LogType"]["Type"];
			}

			void BXML(lua_State* lua, const std::string& ns)
			{
				module(lua, ns.c_str())
					[
						def("LoadFromFile", &sl::LoadFromFile),
						def("SaveToFile", &sl::SaveToFile)
					];
			}

			void Bind(lua_State* lua, const std::string& ns)
			{
				open(lua);
				BCode(lua, ns);
				BLogger(lua, ns);
				BXML(lua, ns);

				//sl::Lua->Execute("print = function(msg)\n\tif type(msg) == 'table' then\n\t\tfor i, k in pairs(msg) do\n\t\t\tprint(k)\n\t\tend\n\telse\n\t\tsl.LogManager:Get('stdout'):Write(tostring(msg))\n\tend\nend");
				sl::Lua->Execute("print = function(...)\n\tsl.LogManager:Get('stdout'):Write(table.concat(arg, ', '))\nend");
				sl::Lua->Execute("function sl.EnumToString(enum, code)\n\tfor i, k in pairs(enum) do\n\t\tif k == code then\n\t\t\treturn i\n\t\tend\n\tend\n\treturn ''\nend");
			}
		}
	}
}